/*
 ----------------------------------------------------------------------------------
                           "THE BEER-WARE COPYRIGHT LICENSE"
                                     (Revision 43)
                                      -----------
    Rymek [rymek@rymek.org] wrote this file. As long as You retain this notice and
    this file has been sent directly to You by the author, You can do whatever You
    want with this stuff as long as You don't sell or rent it. If we meet some day,
    and You think this stuff is worth it, You can buy me a beer in return :-)
                                                                 __________
                                                                 Paweł Rymaszewski
  ----------------------------------------------------------------------------------
 */

package processing.logic.util;

import constants.Constants;
import constants.MessageConstants;
import constants.QueryConstants;
import constants.UiConstants;
import processing.objects.Result;
import processing.objects.SearchParameters;
import processing.objects.Server;
import utils.properties.Configuration;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * Class containing utils for mapping Message information
 *
 * @author rymek
 *         User: rymek
 *         Date: 29.06.11
 *         Time: 12:34
 */
public class Mapper {

    /**
     * Builds query for fetching message body
     *
     * @param searchParameters search parameters
     * @param id               message identifier: guid for sync messages / pubid for async messages
     * @param connection       connection to create statement for
     * @return database query
     * @throws SQLException when Database Access Error occurs
     */
    public static PreparedStatement buildPreparedFetchQuery(SearchParameters searchParameters, String id, Connection connection) throws SQLException {

        PreparedStatement preparedFetchQuery = null;
        String dbQuery;

        // building different query for custom publisher messages
        if (searchParameters.getMessageInfo().isCustomPublisher()) {

            preparedFetchQuery = connection.prepareStatement(QueryConstants.CPUBLISHER_MESSAGE_FETCH);
            preparedFetchQuery.setInt(1, searchParameters.getMessageInfo().getServerNbr());
            preparedFetchQuery.setString(2, id);

        } else {

            // building different query for sync and async messages
            switch (searchParameters.getMessageInfo().getMessageType()) {

                case MessageConstants.MSG_SYNC_MESSAGE: {

                    if (searchParameters.includeArchives())
                        dbQuery = QueryConstants.SYNC_MESSAGES_FETCH.substring(0, QueryConstants.SYNC_MESSAGES_FETCH.length() - 1) + QueryConstants.SYNC_MESSAGES_FETCH_ARCHIVES;
                    else dbQuery = QueryConstants.SYNC_MESSAGES_FETCH;

                    preparedFetchQuery = connection.prepareStatement(dbQuery);

                    preparedFetchQuery.setString(1, id);
                    preparedFetchQuery.setInt(2, 1);
                    preparedFetchQuery.setInt(3, 3);

                    if (searchParameters.includeArchives()) {
                        preparedFetchQuery.setString(4, id);
                        preparedFetchQuery.setInt(5, 1);
                        preparedFetchQuery.setInt(6, 3);
                    }

                    break;
                }

                case MessageConstants.MSG_ASYNC_MESSAGE: {

                    if (searchParameters.includeArchives())
                        dbQuery = QueryConstants.ASYNC_MESSAGES_FETCH.substring(0, QueryConstants.ASYNC_MESSAGES_FETCH.length() - 1) + QueryConstants.ASYNC_MESSAGES_FETCH_ARCHIVES;
                    else dbQuery = QueryConstants.ASYNC_MESSAGES_FETCH;

                    preparedFetchQuery = connection.prepareStatement(dbQuery);

                    preparedFetchQuery.setString(1, id);
                    preparedFetchQuery.setString(2, searchParameters.getMessageInfo().getChannelName());

                    if (searchParameters.includeArchives()) {
                        preparedFetchQuery.setString(3, id);
                        preparedFetchQuery.setString(4, searchParameters.getMessageInfo().getChannelName());
                    }
                    break;
                }
            }
        }
        return preparedFetchQuery;
    }

    /**
     * Creates prepared statement for efficiently searching database
     *
     * @param searchParameters search parameters to build statement for
     * @param connection       connection to create statement for
     * @return prepared and compiled sql statement
     * @throws SQLException when Database Access Error occurs
     */
    public static PreparedStatement buildPreparedSearchQuery(SearchParameters searchParameters, Connection connection) throws SQLException {

        PreparedStatement preparedSearchQuery = null;
        String dbQuery;

        // building different query for custom publisher messages
        if (searchParameters.getMessageInfo().isCustomPublisher()) {

            preparedSearchQuery = connection.prepareStatement(QueryConstants.CPUBLISHER_MESSAGE_SEARCH);
            preparedSearchQuery.setString(1, searchParameters.getMessageInfo().getRequestName());
            preparedSearchQuery.setInt(2, searchParameters.getMessageInfo().getServerNbr());
            preparedSearchQuery.setString(3, searchParameters.getDttmFrom());
            preparedSearchQuery.setString(4, searchParameters.getDttmTo());

        } else {

            // building different query for sync and async messages
            switch (searchParameters.getMessageInfo().getMessageType()) {

                case MessageConstants.MSG_SYNC_MESSAGE: {

                    if (searchParameters.includeArchives())
                        dbQuery = QueryConstants.SYNC_MESSAGES_SEARCH.substring(0, QueryConstants.SYNC_MESSAGES_SEARCH.length() - 1) + QueryConstants.SYNC_MESSAGES_SEARCH_ARCHIVES;
                    else dbQuery = QueryConstants.SYNC_MESSAGES_SEARCH;

                    if (Configuration.production)
                        dbQuery = dbQuery.replace(Constants.DB_PUBLISHTIMESTAMP_NAME, Constants.DB_LASTUPDDTTM_NAME);

                    preparedSearchQuery = connection.prepareStatement(dbQuery);

                    preparedSearchQuery.setString(1, searchParameters.getMessageInfo().getRequestName());
                    preparedSearchQuery.setString(2, searchParameters.getDttmFrom());
                    preparedSearchQuery.setString(3, searchParameters.getDttmTo());
                    preparedSearchQuery.setInt(4, Integer.parseInt(searchParameters.getProcessingTime()));
                    preparedSearchQuery.setString(5, searchParameters.getMessageInfo().getNodeName());
                    preparedSearchQuery.setString(6, searchParameters.getMessageInfo().getChannelName());

                    if (searchParameters.includeArchives()) {
                        preparedSearchQuery.setString(7, searchParameters.getMessageInfo().getRequestName());
                        preparedSearchQuery.setString(8, searchParameters.getDttmFrom());
                        preparedSearchQuery.setString(9, searchParameters.getDttmTo());
                        preparedSearchQuery.setInt(10, Integer.parseInt(searchParameters.getProcessingTime()));
                        preparedSearchQuery.setString(11, searchParameters.getMessageInfo().getNodeName());
                        preparedSearchQuery.setString(12, searchParameters.getMessageInfo().getChannelName());
                    }
                    break;
                }

                case MessageConstants.MSG_ASYNC_MESSAGE: {
                    if (searchParameters.includeArchives())
                        dbQuery = QueryConstants.ASYNC_MESSAGES_SEARCH.substring(0, QueryConstants.ASYNC_MESSAGES_SEARCH.length() - 1) + QueryConstants.ASYNC_MESSAGES_SEARCH_ARCHIVES;
                    else dbQuery = QueryConstants.ASYNC_MESSAGES_SEARCH;

                    if (Configuration.production)
                        dbQuery = dbQuery.replace(Constants.DB_PUBLISHTIMESTAMP_NAME, Constants.DB_LASTUPDDTTM_NAME);

                    preparedSearchQuery = connection.prepareStatement(dbQuery);

                    preparedSearchQuery.setString(1, searchParameters.getMessageInfo().getRequestName());
                    preparedSearchQuery.setString(2, searchParameters.getDttmFrom());
                    preparedSearchQuery.setString(3, searchParameters.getDttmTo());
                    preparedSearchQuery.setInt(4, Integer.parseInt(searchParameters.getProcessingTime()));
                    preparedSearchQuery.setString(5, searchParameters.getMessageInfo().getChannelName());
                    preparedSearchQuery.setString(6, searchParameters.getMessageInfo().getNodeName());

                    if (searchParameters.includeArchives()) {
                        preparedSearchQuery.setString(7, searchParameters.getMessageInfo().getRequestName());
                        preparedSearchQuery.setString(8, searchParameters.getDttmFrom());
                        preparedSearchQuery.setString(9, searchParameters.getDttmTo());
                        preparedSearchQuery.setInt(10, Integer.parseInt(searchParameters.getProcessingTime()));
                        preparedSearchQuery.setString(11, searchParameters.getMessageInfo().getChannelName());
                        preparedSearchQuery.setString(12, searchParameters.getMessageInfo().getNodeName());
                    }
                    break;
                }
            }
        }
        return preparedSearchQuery;
    }

    /**
     * Method builds header that is added for each fetched message
     *
     * @param result result to build header for
     * @param server source database for this message
     * @return header string
     */
    public static String generateMessageHeader(Result result, Server server) {

        String header = UiConstants.HDR_LINE_SEPARATOR;

        // building different header for sync/async messages
        switch (result.getMessageInfo().getMessageType()) {


            case MessageConstants.MSG_SYNC_MESSAGE: {

                // building different header for synchronous request/response
                switch (result.getLogtype()) {

                    case MessageConstants.MSG_REQUEST: {
                        header = header + UiConstants.HDR_MSG_NAME + result.getMessageInfo().getRequestName() + "\n";
                        header = header + UiConstants.HDR_MSG_GUID + result.getId() + "\n";
                        header = header + UiConstants.HDR_MSG_PUBTIMESTAMP + Configuration.dttmFormat.format(result.getMsgRcvDttm()) + "\n";
                        header = header + UiConstants.HDR_MSG_LASTUPDDTTM + Configuration.dttmFormat.format(result.getMsgRspDttm()) + "\n";
                        header = header + UiConstants.HDR_MSG_PROCESSING_TIME + result.getProcessingTime() + " sec.\n";
                        header = header + UiConstants.HDR_MSG_SRC_DATABSE + server.getTnsName() + "\n";
                        break;
                    }
                    case MessageConstants.MSG_RESPONSE: {
                        header = header + UiConstants.HDR_MSG_NAME + result.getMessageInfo().getResponseName() + "\n";
                        header = header + UiConstants.HDR_MSG_GUID + result.getId() + "\n";
                        header = header + UiConstants.HDR_MSG_LASTUPDDTTM + Configuration.dttmFormat.format(result.getMsgRspDttm()) + "\n";
                        header = header + UiConstants.HDR_MSG_PROCESSING_TIME + result.getProcessingTime() + " sec.\n";
                        header = header + UiConstants.HDR_MSG_SRC_DATABSE + server.getTnsName() + "\n";
                        break;
                    }
                }
                break;
            }

            case MessageConstants.MSG_ASYNC_MESSAGE: {
                header = header + UiConstants.HDR_MSG_NAME + result.getMessageInfo().getRequestName() + "\n";
                header = header + UiConstants.HDR_MSG_PUBID + result.getId() + "\n";
                header = header + UiConstants.HDR_MSG_PUBTIMESTAMP + Configuration.dttmFormat.format(result.getMsgRcvDttm()) + "\n";
                header = header + UiConstants.HDR_MSG_PROCESSING_TIME + result.getProcessingTime() + " sec.\n";
                header = header + UiConstants.HDR_MSG_SRC_DATABSE + server.getTnsName() + "\n";
                break;
            }
        }

        header = header + UiConstants.HDR_LINE_SEPARATOR + "\n";

        return header;
    }

    /**
     * Generates name of the result file
     *
     * @param result input result for which name will be generated
     * @param server source database for message
     * @return File Name
     */
    public static String generateMessageFileName(Result result, Server server) {

        String fileName = "";

        switch (result.getMessageInfo().getMessageType()) {

            case MessageConstants.MSG_SYNC_MESSAGE: {

                switch (result.getLogtype()) {
                    case MessageConstants.MSG_REQUEST: {
                        fileName = result.getMessageInfo().getRequestName() + "_" + result.getId() + "_" + server.getTnsName() + Constants.RESULT_FILE_EXTENSION;
                        break;
                    }

                    case MessageConstants.MSG_RESPONSE: {
                        fileName = result.getMessageInfo().getResponseName() + "_" + result.getId() + "_" + server.getTnsName() + Constants.RESULT_FILE_EXTENSION;
                        break;
                    }
                }
                break;
            }

            case MessageConstants.MSG_ASYNC_MESSAGE: {
                fileName = result.getMessageInfo().getRequestName() + "_" + result.getId() + "_" + server.getTnsName() + Constants.RESULT_FILE_EXTENSION;
                break;
            }
        }
        return fileName;
    }

    /**
     * Method maps message type (Synchronous/Asynchronous) from
     * Transaction type string (IA, OA, IS, OS)
     *
     * @param trx transaction type
     * @return message type
     */
    public static int mapMessageTypeFromTransaction(String trx) {

        // determining message type from transaction type
        if (trx.contains(MessageConstants.MSG_TRX_INBOUND_ASYNCHRONOUS))
            return MessageConstants.MSG_ASYNC_MESSAGE;
        if (trx.contains(MessageConstants.MSG_TRX_OUTBOUND_ASYNCHRONOUS))
            return MessageConstants.MSG_ASYNC_MESSAGE;
        if (trx.contains(MessageConstants.MSG_TRX_INBOUND_SYNCHRONOUS))
            return MessageConstants.MSG_SYNC_MESSAGE;
        if (trx.contains(MessageConstants.MSG_TRX_OUTBOUND_SYNCHRONOUS))
            return MessageConstants.MSG_SYNC_MESSAGE;

        return 0;
    }

    /**
     * Maps transaction type from short transaction string
     *
     * @param trx short transaction string
     * @return long transaction string
     */
    public static String mapTransactionType(String trx) {

        if (trx.contains(MessageConstants.MSG_TRX_INBOUND_ASYNCHRONOUS))
            return MessageConstants.MSG_STR_TRX_IA;
        if (trx.contains(MessageConstants.MSG_TRX_OUTBOUND_ASYNCHRONOUS))
            return MessageConstants.MSG_STR_TRX_OA;
        if (trx.contains(MessageConstants.MSG_TRX_INBOUND_SYNCHRONOUS))
            return MessageConstants.MSG_STR_TRX_IS;
        if (trx.contains(MessageConstants.MSG_TRX_OUTBOUND_SYNCHRONOUS))
            return MessageConstants.MSG_STR_TRX_OS;

        return "";
    }

    /**
     * Parses message string status
     *
     * @param status String status
     * @return true if message is active, false if it's not
     */
    public static boolean mapMessageStatus(String status) {

        switch (status) {
            case MessageConstants.MSG_ACTIVE_STATUS: {
                return true;
            }

            case MessageConstants.MSG_INACTIVE_STATUS: {
                return false;
            }
        }
        return false;
    }
}
